-- 定时器

local skynet = require "skynet"
local filelog = require "filelog"
local timer = require "timer"
local tabletool = require "tabletool"
local timetool = require "timetool"
require "zrdice3enum"

local filename = "tabletimer.lua"

local json = require "cjson"
json.encode_sparse_array(true, 1, 1)

local TableTimer = {}
local CMD = { }
local service = {}
local tableobj = nil
local tablelogic = nil
local gamelogic = nil

--[Comment]
-- init
--
function TableTimer.init(caller)
	service = caller
	tableobj = service.table_data
	tablelogic = service:get_logicbyname("tablelogic")
	gamelogic = service:get_logicbyname("gamelogic")
end

--[Comment]
-- 处理发来的timer命令消息
--
function TableTimer.timer( msgname, ...)
    local f = CMD[msgname]
    if f == nil then
        return
    end
    return f(...)
end

-----------------------------

--[Comment]
-- 一局游戏开始
--
function CMD.onegamestart(timerid, request)
    if timerid ~= tableobj.timer_id then
		return
	end
    tableobj.timer_id = -1

    if tableobj.state ~= EDICETableState.TABLE_STATE_WAIT_ONE_GAME_START then
        return
    end

    tableobj.state = EDICETableState.TABLE_STATE_ONE_GAME_START
    gamelogic.run(tableobj.gameobj)
end

--[Comment]
-- 摇骰子
--
function CMD.shake_dice(timerid, request)
	if timerid ~= tableobj.timer_id then
		return
	end
    tableobj.timer_id = -1

	if tableobj.state ~= EDICETableState.TABLE_STATE_WAIT_SHAKE_DICE then
		return
	end
	
	tableobj.state = EDICETableState.TABLE_STATE_SHAKE_DICE
	gamelogic.run(tableobj.gameobj)	
end

--[Comment]
-- 玩家下注
--
function CMD.playerbet(timerid, request)
	if timerid ~= tableobj.timer_id then
		return
	end
    tableobj.timer_id = -1

	if tableobj.state ~= EDICETableState.TABLE_STATE_WAIT_PLAYER_BET then
		return
	end
	
    tableobj.state = EDICETableState.TABLE_STATE_PLAYER_BET
	gamelogic.run(tableobj.gameobj)	
end

--[Comment]
-- 转动倒计时
--
function CMD.spin_countdown(timerid, request)
	if timerid ~= tableobj.timer_id then
		return
	end

	if tableobj.state ~= EDICETableState.TABLE_STATE_WAIT_OPENCARD_COUNTDOWN then
		return
	end
	tableobj.timer_id = -1

    --下注结束时通知一次下注列表情况
    CMD.notice_totalbet_list(tableobj.notice_betlist_timer)

    --统计下注玩家数,总下注次数
    tableobj.cur_bet_player_num = 0
    tableobj.cur_total_bet_cnt = 0
    tableobj.cur_player_total_bet_cnt = 0
    tableobj.cur_robot_total_bet_cnt = 0
    for _,seat in pairs(tableobj.seats) do
        if seat.state > EDICESeatState.SEAT_STATE_NO_PLAYER and seat.rid > 0 and seat.had_ready then
            if seat.cur_bet_list and seat.cur_total_bet > 0 then
                seat.state = EDICESeatState.SEAT_STATE_PLAYING
                tableobj.cur_bet_player_num = tableobj.cur_bet_player_num + 1
                tableobj.cur_total_bet_cnt = tableobj.cur_total_bet_cnt + seat.cur_bet_cnt
                if seat.is_robot then
                    tableobj.cur_robot_total_bet_cnt = tableobj.cur_robot_total_bet_cnt + seat.cur_bet_cnt
                else
                    tableobj.cur_player_total_bet_cnt = tableobj.cur_player_total_bet_cnt + seat.cur_bet_cnt
                end
            elseif seat.is_banker then
                seat.cur_bet_list = tablelogic.gen_bet_list(tableobj)
                seat.state = EDICESeatState.SEAT_STATE_PLAYING
            else
                seat.state = EDICESeatState.SEAT_STATE_INGAME_WATCH
            end
        end
    end
    
    --统计总下注值
    tableobj.cur_total_bet_num = 0
    tableobj.cur_robot_total_bet_num = 0
    tableobj.cur_player_total_bet_num = 0
    for k,v in pairs(tableobj.cur_total_bet_list) do
        tableobj.cur_total_bet_num = tableobj.cur_total_bet_num + v
        tableobj.cur_robot_total_bet_num = tableobj.cur_robot_total_bet_num + tableobj.cur_robot_total_bet_list[k]
        tableobj.cur_player_total_bet_num = tableobj.cur_player_total_bet_num + tableobj.cur_player_total_bet_list[k]
    end

    tableobj.state = EDICETableState.TABLE_STATE_OPENCARD_COUNTDOWN
	gamelogic.run(tableobj.gameobj)	
end

--[Comment]
-- 执行转动
--
function CMD.dodice(timerid, request)
	if timerid ~= tableobj.timer_id then
		return
	end
    tableobj.timer_id = -1

	if tableobj.state ~= EDICETableState.TABLE_STATE_WAIT_OPEN_DICE then
		return
	end
    if tableobj.table_type == EDICETableType.TABLE_TYPE_ZRSX then
        --下注结束时通知一次下注列表情况
        CMD.notice_totalbet_list(tableobj.notice_betlist_timer)

        --统计下注玩家数,总下注次数
        tableobj.cur_bet_player_num = 0
        tableobj.cur_total_bet_cnt = 0
        tableobj.cur_player_total_bet_cnt = 0
        tableobj.cur_robot_total_bet_cnt = 0
        for _,seat in pairs(tableobj.seats) do
            if seat.state > EDICESeatState.SEAT_STATE_NO_PLAYER and seat.rid > 0 and seat.had_ready then
                if seat.cur_bet_list and seat.cur_total_bet > 0 then
                    seat.state = EDICESeatState.SEAT_STATE_PLAYING
                    tableobj.cur_bet_player_num = tableobj.cur_bet_player_num + 1
                    tableobj.cur_total_bet_cnt = tableobj.cur_total_bet_cnt + seat.cur_bet_cnt
                    if seat.is_robot then
                        tableobj.cur_robot_total_bet_cnt = tableobj.cur_robot_total_bet_cnt + seat.cur_bet_cnt
                    else
                        tableobj.cur_player_total_bet_cnt = tableobj.cur_player_total_bet_cnt + seat.cur_bet_cnt
                    end
                elseif seat.is_banker then
                    seat.cur_bet_list = tablelogic.gen_bet_list(tableobj)
                    seat.state = EDICESeatState.SEAT_STATE_PLAYING
                else
                    seat.state = EDICESeatState.SEAT_STATE_INGAME_WATCH
                end
            end
        end
    
        --统计总下注值
        tableobj.cur_total_bet_num = 0
        tableobj.cur_robot_total_bet_num = 0
        tableobj.cur_player_total_bet_num = 0
        for k,v in pairs(tableobj.cur_total_bet_list) do
            tableobj.cur_total_bet_num = tableobj.cur_total_bet_num + v
            tableobj.cur_robot_total_bet_num = tableobj.cur_robot_total_bet_num + tableobj.cur_robot_total_bet_list[k]
            tableobj.cur_player_total_bet_num = tableobj.cur_player_total_bet_num + tableobj.cur_player_total_bet_list[k]
        end
        --真人场通知游戏状态
        local msg = { game_state = EGameState.GAME_STATE_STOP_BET }
        tablelogic.sendmsg_to_alltableplayer(tableobj, "gamestatechangeN", msg)
        
        local msg = { game_state = EGameState.GAME_STATE_OPEN_CARD}
        tablelogic.sendmsg_to_alltableplayer(tableobj, "gamestatechangeN", msg)

        tableobj.state = EDICETableState.TABLE_STATE_WAIT_HANDLE_OPEN_DICE_RESULT
    else
        tableobj.state = EDICETableState.TABLE_STATE_OPEN_DICE
	    gamelogic.run(tableobj.gameobj)
    end
end

--[Comment]
-- 处理转动结果
--
function CMD.handle_diceresult(timerid, request)
	if timerid ~= tableobj.timer_id then
		return
	end
    tableobj.timer_id = -1

	if tableobj.state ~= EDICETableState.TABLE_STATE_WAIT_HANDLE_OPEN_DICE_RESULT then
		return
	end
    if tableobj.table_type ~= EDICETableType.TABLE_TYPE_ZRSX then
        --下注结束时通知一次下注列表情况
        CMD.notice_totalbet_list(tableobj.notice_betlist_timer)

        --统计下注玩家数,总下注次数
        tableobj.cur_bet_player_num = 0
        tableobj.cur_total_bet_cnt = 0
        tableobj.cur_player_total_bet_cnt = 0
        tableobj.cur_robot_total_bet_cnt = 0
        for _,seat in pairs(tableobj.seats) do
            if seat.state > EDICESeatState.SEAT_STATE_NO_PLAYER and seat.rid > 0 and seat.had_ready then
                if seat.cur_bet_list and seat.cur_total_bet > 0 then
                    seat.state = EDICESeatState.SEAT_STATE_PLAYING
                    tableobj.cur_bet_player_num = tableobj.cur_bet_player_num + 1
                    tableobj.cur_total_bet_cnt = tableobj.cur_total_bet_cnt + seat.cur_bet_cnt
                    if seat.is_robot then
                        tableobj.cur_robot_total_bet_cnt = tableobj.cur_robot_total_bet_cnt + seat.cur_bet_cnt
                    else
                        tableobj.cur_player_total_bet_cnt = tableobj.cur_player_total_bet_cnt + seat.cur_bet_cnt
                    end
                elseif seat.is_banker then
                    seat.cur_bet_list = tablelogic.gen_bet_list(tableobj)
                    seat.state = EDICESeatState.SEAT_STATE_PLAYING
                else
                    seat.state = EDICESeatState.SEAT_STATE_INGAME_WATCH
                end
            end
        end
    
        --统计总下注值
        tableobj.cur_total_bet_num = 0
        tableobj.cur_robot_total_bet_num = 0
        tableobj.cur_player_total_bet_num = 0
        for k,v in pairs(tableobj.cur_total_bet_list) do
            tableobj.cur_total_bet_num = tableobj.cur_total_bet_num + v
            tableobj.cur_robot_total_bet_num = tableobj.cur_robot_total_bet_num + tableobj.cur_robot_total_bet_list[k]
            tableobj.cur_player_total_bet_num = tableobj.cur_player_total_bet_num + tableobj.cur_player_total_bet_list[k]
        end
    end
    tableobj.state = EDICETableState.TABLE_STATE_HANDLE_OPEN_DICE_RESULT
	gamelogic.run(tableobj.gameobj)	
end

--[Comment]
----一局游戏结束
--
function CMD.onegameend(timerid, request)
	if tableobj.timer_id ~= timerid then
		return
	end
	
	tableobj.timer_id = -1
	tableobj.state = EDICETableState.TABLE_STATE_ONE_GAME_END
	gamelogic.run(tableobj.gameobj)
end


--[Comment]
-- 一局游戏真正结束
--
function CMD.onegamerealend(timerid, request)
	if timerid ~= tableobj.timer_id then
		return
	end
    tableobj.timer_id = -1

	if tableobj.state ~= EDICETableState.TABLE_STATE_WAIT_ONE_GAME_REAL_END then
		return
	end

	tableobj.state = EDICETableState.TABLE_STATE_ONE_GAME_REAL_END
	gamelogic.run(tableobj.gameobj)	
end

--[Comment]
-- 准备
--
function CMD.doready(timerid, request)
	local seat = tableobj.seats[request.seat_index]	
	if seat.rid ~= request.rid then
		return
	end
	if timerid ~= seat.ready_timer_id then 
		return
	end
    seat.ready_timer_id = -1

    --超时自动准备
    local request = { table_index = tableobj.index}
    local roledata = { info = {rid = seat.rid}, money = { diamond = seat.playerinfo.diamond}, }
    local ret = skynet.call(tableobj.table_service,"lua","request","gameready",seat.rid,roledata,request)
    if not ret or ret.retcode ~= nil then
        --准备失败将玩家站起，并踢出房间
        filelog.sys_error("--auto gameready failed!--", seat.rid, ret)
	    seat.ready_to_time = nil
        seat.ready_timeout_time = nil
        if tablelogic.is_diamondtable() or tablelogic.is_cointable() then
            local rid,coin = seat.rid,tablelogic.get_curmoney(seat)
	        tablelogic.passive_standuptable(tableobj, request, seat, EStandupReason.STANDUP_REASON_READYTIMEOUT_STANDUP)	
            tablelogic.passive_leavetable(tableobj,rid,coin)
        end
    end
end

--[Comment]
-- 删除桌子
--
function CMD.delete_table(timerid, request)
    if tableobj.delete_table_timer_id == timerid then
        local timeout = 1
        if tableobj.table_type ~= EDICETableType.TABLE_TYPE_COIN then
            timeout = tableobj.table_persist or 10 --默认10s
        end
        tableobj.delete_table_timer_id = timer.settimer(timeout * 100,"real_delete_table")
    end 
end

--[Comment]
-- 真正删除桌子
--
function CMD.real_delete_table(timerid, request)
    if tableobj.delete_table_timer_id == timerid then
        tableobj.delete_table_timer_id = -1
        --保存游戏记录
        if tableobj.game_records and tableobj.game_records.delete_reason == 0 then
            tableobj.game_records.end_time = tableobj.one_end_time or 0
            tableobj.game_records.final_to_num = tableobj.curr_to_num or 0
            tableobj.game_records.delete_reason = EDICETableDeleteReason.DELETE_REASON_TABLE_NO_PLAYER
        end
        skynet.send(tableobj.table_service,"lua", "delete")
    end 
end

--[Comment]
-- 延迟处理断线重连
--
function CMD.reenter_table(timerid,request)
    local seat = tableobj.seats[request.seat_index]
    tablelogic.reentertable(tableobj,nil,seat)
end

--[Comment]
-- 旁观
--
function CMD.do_watch(timerid, request)
    if not request or request.rid == nil then
        return
    end

    if tableobj.waits[request.rid] ~= nil then
        tablelogic.passive_leavetable(tableobj, request.rid, request.coin)
    end
end

--[Comment]
-- 断线超时
--
function CMD.disconnect_outtime(timerid, request)
    if not request or request.index == nil then
        return
    end

    local seat = tableobj.seats[request.index]
    if not seat then
        return
    end
    seat.disconnect_timer_id = -1

    local rid,coin = seat.rid,tablelogic.get_curmoney(seat)
    tablelogic.passive_standuptable(tableobj, {}, seat, EStandupReason.STANDUP_REASON_DISCONNECTED)	
    tablelogic.passive_leavetable(tableobj,rid,coin)
    
end

--[Comment]
-- 保存记录
--
function CMD.save_records(timerid, request)
    gamelogic.save_records(tableobj)
end


--[Comment]
-- 通知总下注列表
--
function CMD.notice_totalbet_list(timerid, request)
    if timerid ~= tableobj.notice_betlist_timer then
        return
    end
    tableobj.notice_betlist_timer = -1

    local total_bet_list = { }
    for k,v in pairs(tableobj.cur_total_bet_list) do
        table.insert(total_bet_list,{item_id = k, total_bet = v})
    end

    --剔除特权位的下注变化
    local special_seats_num = tableobj.special_seats_num or 4
    local last_bet_inc_list = nil
    local last_special_seat_rid = nil
    local speseat_betchange_list = {}
    for i,seat_index in ipairs(tableobj.special_seats) do
        local bet_inc_list = {}
        local speseat = tableobj.seats[seat_index] or {}
        if speseat.rid > 0 then
            speseat.cur_betcnt_inc_list = speseat.cur_betcnt_inc_list or {}
            for i,item in ipairs(total_bet_list) do
                local k = item.item_id
                if tableobj.each_inc_bet_cnt_list[k] and speseat.cur_betcnt_inc_list[k] then
                    bet_inc_list[k] = 0
                    local arr = tableobj.each_inc_bet_cnt_list[k]
                    local seat_inc_list = speseat.cur_betcnt_inc_list[k]
                    for score,cnt in pairs(arr) do
                        arr[score] = cnt - (seat_inc_list[score] or 0)
                        bet_inc_list[k] = bet_inc_list[k] + score * (seat_inc_list[score] or 0)
                    end
                end
            end
            speseat.cur_betcnt_inc_list = {}
        end
        speseat_betchange_list[speseat.rid] = bet_inc_list
        if i > special_seats_num then
            last_special_seat_rid = speseat.rid
            last_bet_inc_list = tabletool.deepcopy(bet_inc_list)
            break
        end
    end

    --计算剩余下注
    local banker_seat = tableobj.seats[tableobj.banker_seat_index] or tableobj.sys_banker_info
    local banker_money = tablelogic.get_curmoney(banker_seat)
    local init_money = (banker_seat.cur_downbanker_money - tableobj.conf.up_banker_money + 1)
    local total_bet = tableobj.cur_total_bet_num
    local real_money = banker_money - init_money
    local max_bet = math.floor(real_money / 100) * 100
    tableobj.remain_total_bet_num = max_bet - total_bet

    --通知每一个玩家
    for _,seat in pairs(tableobj.seats) do
        if seat.state > 1 and seat.rid > 0 then
            local cur_total_bet_list = {}
            seat.cur_betcnt_inc_list = seat.cur_betcnt_inc_list or {}
            for i,item in ipairs(total_bet_list) do
                local k = item.item_id
                local change_list = {}
                local cur_inc_betvalue = 0
                if tableobj.each_inc_bet_cnt_list[k] then
                    local arr = tableobj.each_inc_bet_cnt_list[k]
                    local seat_inc_list = seat.cur_betcnt_inc_list[k] or {}
                    for score,cnt in pairs(arr) do
                        change_list[score] = cnt - (seat_inc_list[score] or 0)
                        cur_inc_betvalue = cur_inc_betvalue + change_list[score] * score
                    end
                end
                change_list = json.encode(change_list)
                if not speseat_betchange_list[seat.rid] and last_bet_inc_list then
                    cur_inc_betvalue = cur_inc_betvalue + (last_bet_inc_list[k] or 0)
                end
                table.insert(cur_total_bet_list,{item_id = k, total_bet = item.total_bet, cur_inc_betvalue = cur_inc_betvalue})
            end
            local sp_betchange_list = nil
            if not speseat_betchange_list[seat.rid] and last_bet_inc_list then
                local tmp_item = speseat_betchange_list[last_special_seat_rid]
                speseat_betchange_list[last_special_seat_rid] = nil
                sp_betchange_list = json.encode(speseat_betchange_list)
                speseat_betchange_list[last_special_seat_rid] = tmp_item
            elseif speseat_betchange_list[seat.rid] then
                local tmp_item = speseat_betchange_list[seat.rid]
                speseat_betchange_list[seat.rid] = nil
                sp_betchange_list = json.encode(speseat_betchange_list)
                speseat_betchange_list[seat.rid] = tmp_item
            else
                sp_betchange_list = json.encode(speseat_betchange_list)
            end
            seat.cur_betcnt_inc_list = {}
            tablelogic.sendmsg_to_tableplayer(seat.rid,"betlistchangeN",{
                cur_total_bet_list = cur_total_bet_list,
                speseat_betchange_list = sp_betchange_list,
                cur_total_bet_num = tableobj.cur_total_bet_num,
                remain_total_bet_num = tableobj.remain_total_bet_num,
            })
        end
    end
    tableobj.each_inc_bet_cnt_list = {}
end

function TableTimer.check_outime(timerid, request)
    if timerid ~= tableobj.checkoutime_timer_id then
        return
    end
    tableobj.checkoutime_timer_id = -1
    
    if not request or request.state == tableobj.state then
        return
    end
    
    --通知断线
    local noticemsg = { game_state = EBJLGameState.GAME_STATE_DISCONNECT, }
    tablelogic.sendmsg_to_alltableplayer(tableobj, "gamestatechangeN", noticemsg)
end

return TableTimer